package com.bbzn.device.client.service.impl.cwting;

import com.alibaba.fastjson.JSONObject;
import com.bbzn.device.client.config.EmqCode;
import com.bbzn.device.client.config.EmqxMqttProperties;
import com.bbzn.device.client.config.Oauth2Constant;
import com.bbzn.device.client.constant.TitleConstant;
import com.bbzn.device.client.dao.mqttsub.EmqApiPublishEntity;
import com.bbzn.device.client.dataobject.*;
import com.bbzn.device.client.dto.ct.data.ProductUnionDTO;
import com.bbzn.device.client.dto.ct.request.RequestCreateCommand;
import com.bbzn.device.client.dto.ct.response.ResponseCommand;
import com.bbzn.device.client.dto.device.DeviceDTO;
import com.bbzn.device.client.service.*;
import com.bbzn.device.client.service.emq.OrderSendService;
import com.bbzn.device.client.utils.*;
import com.bbzn.device.client.utils.app.push.UmengUtil;
import com.bbzn.user.client.UserClient;
import com.bbzn.user.comment.User;
import com.ctg.ag.sdk.biz.aep_device_command.CreateCommandResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

/**
 * @Author wulongbo
 * @Date 2021/9/10 15:49
 * @Version 1.0
 */
@Slf4j
public class BaseCwtingService {

    @Autowired
    private RedisUtils redisUtil;

    @Resource
    private AlarmHisService alarmHisService;

    @Resource
    private AlarmHisEnService alarmHisEnService;

    @Resource
    private AlarmCnEnService alarmCnEnService;

    @Resource
    private DeviceService deviceService;

    @Resource
    private UserClient userClient;

    @Resource
    private SwitchService switchService;

    @Resource
    private NbPublishService nbPublishService;

    @Resource
    private ToEmailService toEmailService;

    @Autowired
    private GroupDeviceService groupDeviceService;

    @Autowired
    private PublishService publishService;

    @Autowired
    private DeviceShareService deviceShareService;

    @Autowired
    private NbDetailService nbDetailService;

    @Resource
    private EmqxMqttProperties emqxMqttProperties;

    @Autowired
    private EmqApiService emqApiService;


    @Autowired
    @Qualifier("threadPoolExecutorForVideo")
    private Executor executor;

    protected String common(String code, String imei, String cnSign, String enSign, Integer alarmType, String title, String enTitle) throws Exception {
        Device device = deviceService.selByImei(imei);
        if (device == null) {
            return "";
        }
        Long userId = device.getUserId();
        String value = redisUtil.get(String.valueOf(userId));
        User user = userClient.selectByPrimaryKey(userId);

        String operator = user.getUsername();
        if (StringUtils.isEmpty(operator)) {
            operator = user.getPhone();
        }
        // 记录报警历史（中文）
        AlarmHis alarmHis = new AlarmHis();
        alarmHis.setImei(imei);
        // 报警类型（1：设备上线 /  2：设备离线 / 3：围栏正常 / 4：围栏异常/ 5：手环脱落 / 6：手表佩戴 / 7：血压预警  / 8：心率预警 / 9：温度预警 /10：烟雾报警 /11：低电压报警/12：烟雾感应报警 /13：血氧预警 /14：防拆报警）
        alarmHis.setAlarmType(alarmType);
        alarmHis.setCreateTime(new Timestamp(System.currentTimeMillis()));
        alarmHis.setTitle(title);
        alarmHis.setSigh(cnSign);
        alarmHis.setCreatedBy(operator);
        alarmHis.setUserId(userId);
        alarmHis.setValue(code);
        alarmHis.setDeviceCategoryId(device.getDeviceCategoryId());
        alarmHisService.insertSelective(alarmHis);

        // 记录报警历史（EN）
        AlarmHisEn alarmHisEn = new AlarmHisEn();
        alarmHisEn.setImei(imei);
        // 报警类型（1：设备上线 /  2：设备离线 / 3：围栏正常 / 4：围栏异常/ 5：手环脱落 / 6：手表佩戴 / 7：血压预警  / 8：心率预警 / 9：温度预警 /10：烟雾报警 /11：低电压报警/12：烟雾感应报警 /13：血氧预警）
        alarmHis.setAlarmType(alarmType);
        alarmHisEn.setCreateTime(new Timestamp(System.currentTimeMillis()));
        alarmHisEn.setTitle(enTitle);
        alarmHisEn.setSigh(enSign);
        alarmHisEn.setCreatedBy(operator);
        alarmHis.setUserId(userId);
        alarmHisEn.setValue(code);
        alarmHis.setDeviceCategoryId(device.getDeviceCategoryId());
        alarmHisEnService.insertSelective(alarmHisEn);

        // 记录关联关系
        AlarmCnEn alarmCnEn = new AlarmCnEn();
        alarmCnEn.setCnId(alarmHis.getId());
        alarmCnEn.setEnId(alarmHisEn.getId());
        alarmCnEn.setCreateTime(new Timestamp(System.currentTimeMillis()));
        alarmCnEn.setCreatedBy(operator);
        alarmCnEnService.insertSelective(alarmCnEn);

        List<Long> receiveIds = deviceShareService.findReceiveIdByImei(imei);
        List<String> appPushList = new ArrayList<>();
        receiveIds.stream().forEach(
                receiveId -> {
                    String result = redisUtil.get(String.valueOf(receiveId));
                    if (StringUtils.isNotEmpty(result)) {
                        appPushList.add(result);
                    }
                }
        );
        appPushList.add(value);


        // 推送APP
        appPushList.stream().forEach(
                push -> {
                    JSONObject jsonObject = JSONObject.parseObject(push);
                    Integer type = jsonObject.getInteger("type");
                    String pushToken = jsonObject.getString("pushToken");
                    if (OptionalBean.ofNullable(pushToken).isPresent()) {
                        if (type.compareTo(1) == 0) {
                            try {
                                UmengUtil.sendAndroidBroadcast(pushToken, cnSign, TitleConstant.CWTING_SMOKE_ALARM);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                        if (type.compareTo(2) == 0) {
                            try {
                                UmengUtil.sendIOSUnicast(pushToken, cnSign);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
        );


        // web端烟感开关检查
        Switch need = new Switch();
        need.setUserId(userId);
        // 0-ygFlag / 1-mailFlag / 2-smsFlag / 3-phoneFlag
        List<Boolean> booleanList = switchService.checkSwitchByYgObs(need);
        if (booleanList.get(0)) {
            DeviceDTO deviceDTO = new DeviceDTO();
            deviceDTO.setImei(imei);
            List<Long> pushIds = deviceService.getOperatorIdsBySelective(deviceDTO);
            // 异常消息统一推送给web前端
            // 组装json
            JSONObject data = new JSONObject();
            data.put("CN", cnSign);
            data.put("EN", enSign);
            data.put("cid", alarmHis.getId());
            data.put("eid", alarmHisEn.getId());
            data.put("type", code);
            data.put("name", operator);
            data.put("headImg", user.getImgUrl());
            data.put("time", System.currentTimeMillis());

            String payload = data.toJSONString();

            // EMQ 指定客户端主题批量订阅 topic
            String url = emqxMqttProperties.getHostUrl();
            String postUri = Oauth2Constant.EMQ_API_HTTP
                    + url.substring(0, url.lastIndexOf(":")).substring(url.indexOf(":")) + Oauth2Constant.EMQ_API_PUBLISHBATCH_ADR;

            List<EmqApiPublishEntity> mq = pushIds.stream().map(id -> {
                EmqApiPublishEntity entity = new EmqApiPublishEntity();
                entity.setQos(2);
                entity.setTopics(EmqCode.webTopic + id + EmqCode.endTopic);
                entity.setPayload(payload);
                return entity;
            }).collect(Collectors.toList());
            emqApiService.publishBatch(postUri, mq);
        }


        if (booleanList.get(1) && StringUtils.isNotEmpty(user.getEmail())) {
            // 发送邮件
            ToEmail toEmail = new ToEmail();
            toEmail.setSubject("【把把智能科技】"); // 邮件主题
            toEmail.setContent(cnSign); // 邮件内容
            toEmail.setTos(new String[]{user.getEmail()}); // 邮件接收方，可多人
            toEmailService.commonEmail(toEmail);
        }
        // 异常消息！设备号：{1}的烟雾感应报警器发生告警，当前烟雾浓度为{2}OBS/m
        if (booleanList.get(2) && StringUtils.isNotEmpty(user.getPhone())) {
            String[] params = new String[]{imei, String.valueOf("3.1415")};
            // 发送短信
            VerPhoneCodeUtils.emqWebHookSendMessage("86", new String[]{user.getPhone()}, 1024371, params);
        }

        return operator;
    }

    /**
     * 联动
     *
     * @param imei
     * @param operator
     * @throws Exception
     */
    protected void unionDeviceInGroup(String action, String imei, String operator) throws Exception {
        // 1. 查询设备是否分组
        GroupDevice groupDevice = new GroupDevice();
        groupDevice.setImei(imei);
        List<GroupDevice> groupDevices = groupDeviceService.findByAll(groupDevice);
        if (CollectionUtils.isEmpty(groupDevices)) {
            return;
        }
        GroupDevice currentGroup = groupDevices.get(0);
        // 2. 查询本组的其它设备
        List<ProductUnionDTO> productUnionDTOS = groupDeviceService.getInGroupDeviceExceptSelf(imei, currentGroup.getGid());
        if (CollectionUtils.isEmpty(productUnionDTOS)) {
            return;
        }
        // 3. 筛选NB设备
        List<ProductUnionDTO> mq = productUnionDTOS.stream().filter(p -> p.getNBProductId() != null && !p.getContent().isEmpty()).collect(Collectors.toList());
        // 4. NB设备联动
        this.sendOrder(operator, mq);
        // 5. 筛选出非NB设备
        List<ProductUnionDTO> union = productUnionDTOS.stream().filter(p -> p.getNBProductId() == null).collect(Collectors.toList());
        // 6. 非NB设备联动
        if (CollectionUtils.isNotEmpty(union)) {
            NbDetail ygDetail = nbDetailService.selectByPrimaryKey(imei);
            String position;
            if (ygDetail == null || StringUtils.isEmpty(ygDetail.getAddress())) {
                position = "未定义安装位置";
            } else {
                position = ygDetail.getAddress();
            }
            // 记录消息群发操作
            String topic = groupDeviceService.getTopic(groupDevice.getId());
            // 推送立即重启topic给设备
            JSONObject data = new JSONObject();
            data.put("code", EmqCode.massMessaging);
            // 主键id-->只有这条是接收topic需要用到的
            String content = MessageFormat.format("请注意! {position}的{action}", position, action);
            data.put("content", content);
            publishService.sendToMqtt(data.toJSONString(), topic);
        }
    }

    /**
     * 递归构建
     *
     * @param operator
     * @param nbUnion
     */
    private void sendOrder(String operator, List<ProductUnionDTO> nbUnion) {
        if (CollectionUtils.isNotEmpty(nbUnion)) {
            nbUnion.stream().map(nb -> CompletableFuture.supplyAsync(() -> sendCommand(operator, nb), executor)).collect(Collectors.toList());
        }
        return;
    }

    private ProductUnionDTO sendCommand(String operator, ProductUnionDTO nb) {
        // 使用beanid从容器获取对象
        OrderSendService orderSendService = SpringUtils.getBean(nb.getOrderSendStrategy(), OrderSendService.class);
        RequestCreateCommand requestCreateCommand = new RequestCreateCommand();
        requestCreateCommand.setDeviceId(nb.getNbDeviceId());
        requestCreateCommand.setOperator(operator);
        requestCreateCommand.setProductId(nb.getNBProductId().intValue());
        CreateCommandResponse response = null;
        try {
            response = orderSendService.createCommand(nb.getImei(), nb.getMasterKey(), requestCreateCommand, nb.getContent());
            if (response == null) {
                return null;
            }
            // 4.响应结果
            int code = response.getStatusCode();
            if (code != 200) {
                return nb;
            }
            byte[] retBody = response.getBody();
            ResponseCommand responseCommand = JsonUtils.byteToJaveBean(retBody, ResponseCommand.class);
            Integer resCode = responseCommand.getCode();
            if (resCode != 0) {
                return nb;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}
